package edu.ncut.vod.hibernate.service.impl;

import java.sql.Timestamp;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

import edu.ncut.vod.hibernate.dao.DemandedVideoInfoDao;
import edu.ncut.vod.hibernate.dao.ServerInfoDao;
import edu.ncut.vod.hibernate.dao.VideoInfoDao;
import edu.ncut.vod.hibernate.model.DemandedVideoInfo;
import edu.ncut.vod.hibernate.model.Serverinfo;
import edu.ncut.vod.hibernate.service.ServerInfoService;

public class ServerInfoServiceImpl implements ServerInfoService,BeanPostProcessor {             
    
    /*
     * dao layer object named 'videoInfoDao'
     */
    VideoInfoDao videoInfoDao;    

    public VideoInfoDao getVideoInfoDao() {
        return videoInfoDao;
    }

    public void setVideoInfoDao(VideoInfoDao videoInfoDao) {
        this.videoInfoDao = videoInfoDao;
    }
    
    /*
     * dao layer object named 'serverInfoDao'
     */
    ServerInfoDao serverInfoDao;        

    public ServerInfoDao getServerInfoDao() {
        return serverInfoDao;
    }

    public void setServerInfoDao(ServerInfoDao serverInfoDao) {
        this.serverInfoDao = serverInfoDao;
    }
    
    /*
     * dao layer object named 'demandedVideoInfoDao'
     */
    DemandedVideoInfoDao demandedVideoInfoDao;
    
    public DemandedVideoInfoDao getDemandedVideoInfoDao() {
        return demandedVideoInfoDao;
    }

    public void setDemandedVideoInfoDao(DemandedVideoInfoDao demandedVideoInfoDao) {
        this.demandedVideoInfoDao = demandedVideoInfoDao;
    }

    /* output a sentence in console for debugging
     * @see edu.ncut.vod.hibernate.service.ServerInfoService#debug(java.lang.String)
     */
    public void debug(String message) {
        System.out.println(message);
    }

    /* reduce one at column 'curShowNum' in table 'serverinfo'
     * @see edu.ncut.vod.hibernate.service.ServerInfoService#reduceCurShowNumByVideoName(java.lang.String)
     */
    public void reduceCurShowNumByVideoURL(Integer demandedVideoId) {
        debug("method reduceCurShowNumByVideoURL in object ServerInfoServiceImpl is called");
        
        //get column 'videoURL' in table 'demandedvideoinfo'
        DemandedVideoInfo demandedVideoInfo = demandedVideoInfoDao.getDemandedvideoinfo(demandedVideoId);
        String videoUrl = demandedVideoInfo.getVideoUrl();
        /*according to variable 'videoUrl',get object 'serverInfo' and reduce one at column 'curShowNum'
         at last persist this object*/
        List<Serverinfo> serverInfo = serverInfoDao.getServerinfoByVideoURL(videoUrl);
        int temp = Integer.valueOf(serverInfo.get(0).getCurShowNum())-1;//pay attention:there is only one value in List type object 'serverInfo'
        serverInfo.get(0).setCurShowNum(Integer.valueOf(temp));
        serverInfoDao.save(serverInfo.get(0));
        
        debug("temp is "+temp);
    }
    
    /**
     * set zero to column 'isbroadcast' at table 'videoinfo'
     * @param demandedVideoId
     */
    public void setZeroToColumnIsBroadcast(Integer demandedVideoId){
        debug("method setNullToColumnVideoURL in object ServerInfoServiceImpl is called");
        
        //set zero to column 'isbroadcast' at table 'videoinfo' and persist this object
        DemandedVideoInfo demandedVideoInfo = demandedVideoInfoDao.getDemandedvideoinfo(Integer.valueOf(demandedVideoId));
        demandedVideoInfo.setIsBroadcast(0);
        demandedVideoInfoDao.save(demandedVideoInfo);
    }
    
    /**
     * set current time to column 'endtime' at table 'demandedvideoinfo'
     * @param demandedVideoId
     */
    public void setEndTime(Integer demandedVideoId){
        debug("method setEndTime in object ServerInfoServiceImpl is called");
        
        //set current time to column 'endtime' at table 'demandedvideoinfo' and persist this object
        DemandedVideoInfo demandedVideoInfo = demandedVideoInfoDao.getDemandedvideoinfo(Integer.valueOf(demandedVideoId));
        demandedVideoInfo.setEndTime(new Timestamp(System.currentTimeMillis()));
        demandedVideoInfoDao.save(demandedVideoInfo);
    }
    
    /**
     * set state of server
     * @param videoURL
     * @param videoId
     */
    public void setState(Integer demandedVideoId){
        debug("method setState in object ServerInfoServiceImpl is called");
        
        reduceCurShowNumByVideoURL(demandedVideoId);
        setZeroToColumnIsBroadcast(demandedVideoId);
        setEndTime(demandedVideoId);
    }
    
    /**
     * try to find ip of server whose curShowNum is minimum
     * @return id:id of server whose curShowNum is minimum 
     */
    public Integer findCurShowNumMinServer() {
        debug("method findCurShowNumMinServer in object ServerInfoServiceImpl is called");
        
        int min=0;
        Integer id;
        List<Serverinfo> list = serverInfoDao.getServerinfos();
        min = Integer.valueOf(list.get(0).getCurShowNum());
        id = list.get(0).getId();
        for(Serverinfo serverInfo : list){
            if(min>Integer.valueOf(serverInfo.getCurShowNum())){
                min = Integer.valueOf(serverInfo.getCurShowNum());
                id = serverInfo.getId();
            }            
        }
        
        debug("id is " + id);
        
        return id;
    }
    
    /**
     * increase one at row curShowNum
     * @param id:id of server whose curShowNum is minimum 
     */
    public void increaseCurShowNum(Integer serverId){
        debug("method increaseCurShowNum in object ServerInfoServiceImpl is called");
        
        Serverinfo serverInfo = serverInfoDao.getServerinfo(serverId);
        serverInfo.setCurShowNum(serverInfo.getCurShowNum()+1);
        serverInfoDao.save(serverInfo);
    }
    
    /**
     * distribute ServerIp To VideoInformation
     * @param serverId
     * @param videoId
     */
    public void distributeServerIpToVideoInformation(Integer serverId,String videoId,HttpServletRequest request){
        debug("method distributeServerIpToVideoInformation in object ServerInfoServiceImpl is called");
        
        //first get server ip whose column 'curShowNum' is minimum,according to parameter serverId
        Serverinfo serverInfo = serverInfoDao.getServerinfo(serverId);
        String serverIp = serverInfo.getIp();
        
        //second instance an object 'DemandedVideoInfo' and store it in request
        Timestamp beginTime = new Timestamp(System.currentTimeMillis());//time of video start
        Timestamp endTime = null;//time of video end
        DemandedVideoInfo demandedVideoInfo = new DemandedVideoInfo(videoId,serverIp,beginTime,endTime,1);                
        request.setAttribute("demandedVideoInfo",demandedVideoInfo);
        
        //at last,persist this object in database
        demandedVideoInfoDao.save(demandedVideoInfo);
    }
    
    /**
     * first find a row whose column is minimum, and then increase one at column curShowNum
     */
    public Integer updateState(String videoId,HttpServletRequest request){
        debug("method updateState in object ServerInfoServiceImpl is called");
        
        //find a row whose column is minimum
        Integer serverId = findCurShowNumMinServer();
        //increase one at column curShowNum
        increaseCurShowNum(serverId);
        //insert a row in table 'demandedvideoinfo'
        distributeServerIpToVideoInformation(serverId,videoId,request);
        
        return serverId;//id of server whose column 'curShowNum' is minimum 
    }

    /**
     * this method is called on the bean just before this bean is removed from the container
     */
    public void destroy() {
        debug("destroy mothed in ServerInfoServiceImpl object is called");
    }

    /**
     * this method is called on the bean immediately upon instantiation
     */
    public void setup() {
        debug("setup mothed in ServerInfoServiceImpl object is called");
    }
    
    /*
     * the postProcessAfterInitialization() method is called immediately after initialization.
     * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)
     */
    public Object postProcessAfterInitialization(Object arg0, String arg1)
            throws BeansException {
        debug("postProcessAfterInitialization mothed in ServerInfoServiceImpl object is called");
        return null;
    }

    /*
     * The postProcessBeforeInitialization() method is called immediately prior to bean 
     * initialization (the call to afterPropertiesSet() and the bean’s custom initmethod).
     * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String)
     */
    public Object postProcessBeforeInitialization(Object arg0, String arg1)
            throws BeansException {
        debug("postProcessBeforeInitialization mothed in ServerInfoServiceImpl object is called");
        return null;
    }    
}
